home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 23 / develop Issue 23 code / ProjectDrag 1.1b8 / Sources / ProjectDrag Sources / MySignatureToApp.c < prev    next >
Encoding:
Text File  |  1995-07-07  |  9.5 KB  |  350 lines  |  [TEXT/KAHL]

  1. ////
  2. ////    SignatureToApp.c        Implementation of the SignatureToApp function.
  3. ////
  4. ////    By Jens Alfke            ©1991 Apple Computer, Inc. All rights reserved.
  5. ////
  6. ////    Modified by Tim Maroney for ProjectDrag to not search on network volumes,
  7. ////        and (without success) to make sure that LaunchApplication actually worked.
  8. ////
  9.  
  10.  
  11. #include <Errors.h>
  12. #include <Files.h>
  13. #include <Processes.h>
  14. #include <Folders.h>
  15. #include <AppleEvents.h>
  16.  
  17. #include "SignatureToApp.h"
  18.  
  19.  
  20.    ////////////////////////////////////////////////////////////
  21.   //    FindRunningAppBySignature                            //
  22.  //            Search process list for app with this signature//
  23. ////////////////////////////////////////////////////////////
  24. static OSErr
  25. FindRunningAppBySignature( OSType sig, ProcessSerialNumber *psn, FSSpec *fileSpec )
  26. {
  27.     OSErr err;
  28.     ProcessInfoRec info;
  29.     
  30.     psn->highLongOfPSN = 0;
  31.     psn->lowLongOfPSN  = kNoProcess;
  32.     do{
  33.         err= GetNextProcess(psn);
  34.         if( !err ) {
  35.             info.processInfoLength = sizeof(info);
  36.             info.processName = NULL;
  37.             info.processAppSpec = fileSpec;
  38.             err= GetProcessInformation(psn,&info);
  39.         }
  40.     } while( !err && info.processSignature != sig );
  41.  
  42.     if( err )
  43.         fileSpec->name[0] = 0;                                // Clear name if not found
  44.     else
  45.         *psn = info.processNumber;
  46.     return err;
  47. }
  48.  
  49.  
  50.    ////////////////////////////////////////////////////////////
  51.   //    GetSysVolume                                        //
  52.  //            Get the vRefNum of the system (boot) volume       //
  53. ////////////////////////////////////////////////////////////
  54. static OSErr
  55. GetSysVolume( short *vRefNum )
  56. {
  57.     long dir;
  58.     
  59.     return FindFolder(kOnSystemDisk,kSystemFolderType,false, vRefNum,&dir);
  60. }
  61.  
  62.  
  63.    ////////////////////////////////////////////////////////////
  64.   //    GetIndVolume                                        //
  65.  //            Get the vRefNum of an indexed on-line volume   //
  66. ////////////////////////////////////////////////////////////
  67. static OSErr
  68. GetIndVolume( short index, short *vRefNum )
  69. {
  70.     ParamBlockRec pb;
  71.     OSErr err;
  72.     
  73.     pb.volumeParam.ioCompletion = NULL;
  74.     pb.volumeParam.ioNamePtr = NULL;
  75.     pb.volumeParam.ioVolIndex = index;
  76.     
  77.     err= PBGetVInfo(&pb,false);
  78.     
  79.     *vRefNum = pb.volumeParam.ioVRefNum;
  80.     return err;
  81. }
  82.  
  83.  
  84.    ////////////////////////////////////////////////////////////
  85.   //    VolHasDesktopDB                                        //
  86.  //            Check if a volume supports desktop DB calls       //
  87. ////////////////////////////////////////////////////////////
  88. static OSErr
  89. VolHasDesktopDB( short vRefNum, Boolean *hasDesktop )
  90. {
  91.     typedef struct {                        // Volume Info Rec; see IM-VI 25-32
  92.         short    vMVersion;
  93.         long    vMAttrib;
  94.         Handle    vMLocalHand;
  95.         long    vMServerAddr;
  96.         long    vMVolumeGrade;
  97.         short    vMForeignPrivID;
  98.     } VolInfoRec;
  99.     const bHasNewDesk = 1L <<12;            // Flag mask for vMAttrib field
  100.     
  101.     HParamBlockRec pb;
  102.     VolInfoRec info;
  103.     OSErr err;
  104.     
  105.     long i, *ip;
  106.     for( i=0, ip=(long*)&pb; i<sizeof(pb)/sizeof(long); i++ )        // Clear pb
  107.         *ip++ = 0;
  108.     pb.ioParam.ioCompletion = NULL;
  109.     pb.ioParam.ioNamePtr = NULL;
  110.     pb.ioParam.ioVRefNum = vRefNum;
  111.     pb.ioParam.ioBuffer = (Ptr)&info;
  112.     pb.ioParam.ioReqCount = sizeof(VolInfoRec);
  113.     
  114.     err= PBHGetVolParms(&pb,false);            // Get volume info
  115.  
  116.     *hasDesktop = err==noErr && (info.vMAttrib & bHasNewDesk)!=0;
  117.     return err;
  118. }
  119.  
  120.  
  121.    ////////////////////////////////////////////////////////////
  122.   //    FindAppOnVolume                                        //
  123.  //            Ask vol's desktop db for application           //
  124. ////////////////////////////////////////////////////////////
  125. static OSErr
  126. FindAppOnVolume( OSType sig, short vRefNum, FSSpec *file )
  127. {
  128.     DTPBRec pb;
  129.     OSErr err;
  130.     short refNum;
  131.     
  132.     long i, *ip;
  133.     for( i=0, ip=(long*)&pb; i<sizeof(pb)/sizeof(long); i++ )        // Clear pb
  134.         *ip++ = 0;
  135.  
  136.     pb.ioCompletion = NULL;
  137.     pb.ioVRefNum = vRefNum;
  138.     pb.ioNamePtr = NULL;
  139.     err= PBDTGetPath(&pb);                // Puts DT refnum into pb.ioDTRefNum
  140.     if( err ) return err;
  141.     refNum = pb.ioDTRefNum;
  142.     
  143.     pb.ioCompletion = NULL;
  144.     pb.ioDTRefNum = refNum;
  145.     pb.ioIndex = 0;
  146.     pb.ioFileCreator = sig;
  147.     pb.ioNamePtr = (StringPtr)&file->name;
  148.     err= PBDTGetAPPLSync(&pb);                        // Find it!
  149.     
  150.     if( err == fnfErr )
  151.         err = afpItemNotFound;                        // Bug in PBDTGetAPPL
  152.     if( err )
  153.         return err;                                    // Returns afpItemNotFound if app wasn't found.
  154.  
  155.     file->vRefNum = vRefNum;
  156.     file->parID = pb.ioAPPLParID;
  157.     return noErr;
  158. }
  159.  
  160.  
  161.    ////////////////////////////////////////////////////////////
  162.   //    BuildODoc                                            //
  163.  //            Construct an 'odoc' Apple event                   //
  164. ////////////////////////////////////////////////////////////
  165. static OSErr
  166. BuildODoc( const FSSpec *fileSpec, OSType signature, const ProcessSerialNumber *psn,
  167.            AppleEvent *event )
  168. {
  169.     // If psn is non-NULL the event will be addressed to that process;
  170.     // otherwise it'll be addressed to the supplied signature.
  171.     
  172.     AEDesc addr,ev;
  173.     OSErr err;
  174.     
  175.     event->descriptorType = 0;
  176.     event->dataHandle = NULL;
  177.     
  178.     if( psn )
  179.         err= AECreateDesc(typeProcessSerialNumber,(void*)psn,sizeof(*psn), &addr);
  180.     else
  181.         err= AECreateDesc(typeApplSignature,(void*)&signature,sizeof(signature), &addr);
  182.     if( err ) return err;
  183.     
  184.     err= AECreateAppleEvent(kCoreEventClass,kAEOpenDocuments, &addr,kAutoGenerateReturnID,0,&ev);
  185.     AEDisposeDesc(&addr);
  186.     if( !err )
  187.         err= AEPutParamPtr(&ev,keyDirectObject, typeFSS,(void*)fileSpec,sizeof(FSSpec));
  188.     
  189.     if( err )
  190.         AEDisposeDesc(&ev);
  191.     else
  192.         *event = ev;
  193.     return err;
  194. }
  195.  
  196.  
  197.    ////////////////////////////////////////////////////////////
  198.   //    LaunchIt                                            //
  199.  //            Launch app once we have a location               //
  200. ////////////////////////////////////////////////////////////
  201. static OSErr
  202. LaunchIt( const FSSpec *fileSpec, LaunchFlags launchControlFlags, const AppleEvent *odoc,
  203.             ProcessSerialNumber *psn )
  204. {
  205.     LaunchParamBlockRec pb;
  206.     AEDesc paramDesc;
  207.     OSErr err;
  208.     
  209.     pb.launchBlockID = extendedBlock;
  210.     pb.launchEPBLength = extendedBlockLen;
  211.     pb.launchFileFlags = launchNoFileFlags;
  212.     pb.launchControlFlags = launchControlFlags | launchNoFileFlags;
  213.     pb.launchAppSpec = (FSSpec*)fileSpec;
  214.     pb.launchProcessSN.highLongOfPSN = 0;
  215.     pb.launchProcessSN.lowLongOfPSN = 0;
  216.     
  217.     if( odoc ) {
  218.         err= AECoerceDesc(odoc,typeAppParameters, ¶mDesc);
  219.         if( err ) return err;
  220.         HLock(paramDesc.dataHandle);
  221.         pb.launchAppParameters = (void*) *paramDesc.dataHandle;
  222.     } else
  223.         pb.launchAppParameters = NULL;
  224.     
  225.     err= LaunchApplication(&pb);
  226.     
  227.     if( odoc )
  228.         AEDisposeDesc(¶mDesc);
  229.         
  230.     if( err == noErr ) {
  231. #if 0
  232.         // another change by Tim. LaunchApplication sometimes doesn't report
  233.         // an error even though it failed to launch. so check the PSN!
  234.         // this code did not work for some unknown reason.
  235.         ProcessInfoRec info;
  236.         EventRecord event;
  237.         
  238.         WaitNextEvent(0, &event, 0, NULL); // it doesn't launch until this call is made
  239.         info.processInfoLength = sizeof(ProcessInfoRec);
  240.         info.processName = NULL;
  241.         info.processAppSpec = NULL;
  242.         err = GetProcessInformation(&pb.launchProcessSN, &info);
  243.         if (err == noErr)
  244. #endif
  245.             *psn = pb.launchProcessSN;
  246.     }
  247.     return err;
  248. }
  249.  
  250.  
  251.    ////////////////////////////////////////////////////////////
  252.   //    SignatureToApp                                        //
  253.  //            Main routine. Find app, launching if need be   //
  254. ////////////////////////////////////////////////////////////
  255. OSErr
  256. SignatureToApp( OSType sig, const FSSpec *document,
  257.                 ProcessSerialNumber *psn, FSSpec *fileSpec, Boolean *launched,
  258.                 Sig2App_Mode mode,
  259.                 LaunchFlags launchControlFlags )
  260. {
  261.     ProcessSerialNumber dummyPSN;
  262.     OSErr err;
  263.     short sysVRefNum, vRefNum, index;
  264.     FSSpec file;
  265.     Boolean hasDesktopDB;
  266.     
  267.     if( launched )
  268.         *launched = false;
  269.     if( psn == NULL )
  270.         psn = &dummyPSN;                                // Allow psn parameter to be NIL
  271.     
  272.     // First see if it's already running:
  273.     
  274.     err= FindRunningAppBySignature(sig,psn,fileSpec);
  275.     
  276.     if( err==noErr && mode==Sig2App_LaunchApplication ) {
  277.         if( (launchControlFlags & launchDontSwitch) == 0 ) {
  278.             err= SetFrontProcess(psn);                // They wanted to switch to it…
  279.             if( err ) return err;
  280.         }
  281.         if( document ) {
  282.             // They wanna open a document, so do it:
  283.             AppleEvent aevt;
  284.             err= BuildODoc(document,sig,psn, &aevt);
  285.             if( !err )
  286.                 err= AESend(&aevt,NULL,kAENoReply | kAEAlwaysInteract,
  287.                             kAENormalPriority,kAEDefaultTimeout,
  288.                             NULL,NULL);
  289.             AEDisposeDesc(&aevt);
  290.         }
  291.         return err;
  292.     }
  293.  
  294.     if( err != procNotFound || mode<=Sig2App_FindProcess )
  295.         return err;
  296.     
  297.     // Well, it's not running but it's okay to launch it. Let's have a look around:
  298.     
  299.     if( err= GetSysVolume(&sysVRefNum) ) return err;    // Find boot volume
  300.     vRefNum = sysVRefNum;                                // Start search with boot volume
  301.     index = 0;
  302.     do{
  303.         if( index==0 || vRefNum != sysVRefNum ) {
  304.  
  305.             // Here's Tim's change: don't search on network volumes.
  306.             HParamBlockRec pb;
  307.             GetVolParmsInfoBuffer info;
  308.             
  309.             pb.ioParam.ioVRefNum = vRefNum;
  310.             pb.ioParam.ioNamePtr = nil;
  311.             pb.ioParam.ioBuffer = (Ptr)&info;
  312.             pb.ioParam.ioReqCount = sizeof(GetVolParmsInfoBuffer);
  313.             err = PBHGetVolParmsSync(&pb);            // Get volume info
  314.             if (err == noErr && info.vMServerAdr == 0) {
  315.         
  316.                 if( err= VolHasDesktopDB(vRefNum,&hasDesktopDB) )
  317.                     return err;
  318.                 if( hasDesktopDB ) {                        // If volume has a desktop DB,
  319.                     err= FindAppOnVolume(sig,vRefNum, &file);        // ask it to find app
  320.                     if( err==noErr ) {
  321.                         // FOUND IT!
  322.                         if( fileSpec )
  323.                             *fileSpec = file;
  324.                         if( mode==Sig2App_LaunchApplication ) {
  325.                             AEDesc odoc;
  326.                             if( document )
  327.                                 err= BuildODoc(document,sig,NULL,&odoc);
  328.                             if( err ) return err;
  329.                             err= LaunchIt(&file,launchControlFlags,        // Launch it!
  330.                                             document ?&odoc :NULL,
  331.                                             psn);
  332.                             if( document )
  333.                                 AEDisposeDesc(&odoc);
  334.                             if( !err && launched )
  335.                                 *launched = true;
  336.                         }
  337.                         return err;
  338.                         
  339.                     } else if( err != afpItemNotFound )
  340.                         return err;
  341.                 }
  342.             }
  343.         }
  344.         err= GetIndVolume(++index,&vRefNum);                // Else go to next volume
  345.     } while( err==noErr );                                // Keep going until we run out of vols
  346.     
  347.     if( err==nsvErr || err==afpItemNotFound )
  348.         err= fnfErr;                                    // File not found on any volume
  349.     return err;
  350. }